// Package config
// 职责范围: 配置解析、默认值、校验、格式转换
// 不负责的工作: 采集逻辑、SNMP 协议交互
package config

import (
	"errors"
	"time"

	"github.com/gosnmp/gosnmp"
)

// SNMPVersion 定义版本枚举（内部管理）
type SNMPVersion string

const (
	Version1  SNMPVersion = "v1"
	Version2c SNMPVersion = "v2c"
	Version3  SNMPVersion = "v3"
)

// SecurityLevel 定义v3安全级别枚举
type SecurityLevel string

const (
	SecLevelNoAuthNoPriv SecurityLevel = "noAuthNoPriv" // 无认证无加密
	SecLevelAuthNoPriv   SecurityLevel = "authNoPriv"   // 有认证无加密
	SecLevelAuthPriv     SecurityLevel = "authPriv"     // 有认证有加密
)

// 认证协议常量（v3专用）
const (
	AuthMD5    = "MD5"
	AuthSHA    = "SHA"
	AuthSHA256 = "SHA256"
)

// 加密协议常量（v3专用）
const (
	PrivDES    = "DES"
	PrivAES    = "AES"
	PrivAES256 = "AES256"
)

// SNMPConfig 配置结构体（包含v3安全参数）
type SNMPConfig struct {
	Version        SNMPVersion `json:"version"`
	Community      string      `json:"community"` // v1/v2c专用
	Port           int         `json:"port"`
	Timeout        int         `json:"timeout"`
	Retries        int         `json:"retries"`
	SourceAddress  string      `json:"source_address"`
	MaxRepetitions int         `json:"max_repetitions"`

	// v3专用安全参数
	Username      string        `json:"username"`       // 安全名称
	SecurityLevel SecurityLevel `json:"security_level"` // 安全级别
	AuthProtocol  string        `json:"auth_protocol"`  // 认证协议
	AuthPassword  string        `json:"auth_password"`  // 认证密码
	PrivProtocol  string        `json:"priv_protocol"`  // 加密协议
	PrivPassword  string        `json:"priv_password"`  // 加密密码
	ContextName   string        `json:"context_name"`   // 上下文名称（可选）
}

// 默认配置（包内私有，区分版本设置默认值）
var (
	defaultV1V2cConfig = SNMPConfig{
		Version:        Version2c,
		Community:      "public",
		Port:           161,
		Timeout:        5,
		Retries:        1,
		MaxRepetitions: 50,
	}
	defaultV3Config = SNMPConfig{
		Version:        Version3,
		Port:           161,
		Timeout:        5,
		Retries:        1,
		MaxRepetitions: 50,
		SecurityLevel:  SecLevelNoAuthNoPriv, // v3默认安全级别
		AuthProtocol:   AuthMD5,              // v3默认认证协议
		PrivProtocol:   PrivDES,              // v3默认加密协议
	}
)

// NewSNMPConfig 工厂函数：创建并初始化配置（外部唯一入口）
func NewSNMPConfig(userInput map[string]interface{}) (*SNMPConfig, error) {
	// 1. 根据版本选择默认配置
	cfg := parseDefaultConfig(userInput)

	// 2. 从用户输入解析配置
	if err := cfg.fromUserInput(userInput); err != nil {
		return nil, err
	}

	// 3. 验证配置合法性
	if err := cfg.Validate(); err != nil {
		return nil, err
	}

	return &cfg, nil
}

// ToGoSNMPOptions 转换为gosnmp客户端配置选项（包含v3适配）
func (c *SNMPConfig) ToGoSNMPOptions() []func(*gosnmp.GoSNMP) {
	return []func(*gosnmp.GoSNMP){
		func(g *gosnmp.GoSNMP) {
			// 通用配置
			g.Version = c.getGoSNMPVersion()
			g.Community = c.Community
			g.Port = uint16(c.Port)
			g.Timeout = c.getTimeoutDuration()
			g.Retries = c.Retries
			g.MaxRepetitions = uint32(c.MaxRepetitions)
			//g.SourceAddress = c.SourceAddress
			g.ContextName = c.ContextName

			// v3专用安全配置
			if c.Version == Version3 {
				g.SecurityModel = gosnmp.UserSecurityModel
				g.SecurityParameters = c.buildV3SecurityParams()

				g.MsgFlags = c.getMsgFlags()
			}
		},
	}
}

// Validate 配置合法性校验（包含v3专用校验）
func (c *SNMPConfig) Validate() error {
	// 通用参数校验
	if c.Port <= 0 || c.Port > 65535 {
		return errors.New("invalid port (must be 1-65535)")
	}
	if c.Timeout < 0 {
		return errors.New("timeout cannot be negative")
	}
	if c.Retries < 0 {
		return errors.New("retries cannot be negative")
	}
	if c.MaxRepetitions <= 0 {
		return errors.New("max repetitions must be positive")
	}

	// 版本专用校验
	switch c.Version {
	case Version1, Version2c:
		// v1/v2c必须有社区字符串，且不允许v3参数
		if c.Community == "" {
			return errors.New("community is required for v1/v2c")
		}
		if c.Username != "" {
			return errors.New("username is not allowed for v1/v2c")
		}
	case Version3:
		// v3必须有用户名，且不允许社区字符串
		if c.Username == "" {
			return errors.New("username is required for v3")
		}
		if c.Community != "" {
			return errors.New("community is not allowed for v3")
		}

		// v3安全级别校验
		switch c.SecurityLevel {
		case SecLevelNoAuthNoPriv:
			// 无认证无加密：不允许认证/加密参数
			if c.AuthProtocol != "" || c.AuthPassword != "" {
				return errors.New("auth parameters not allowed for noAuthNoPriv")
			}
			if c.PrivProtocol != "" || c.PrivPassword != "" {
				return errors.New("priv parameters not allowed for noAuthNoPriv")
			}
		case SecLevelAuthNoPriv:
			// 有认证无加密：必须有认证参数，不允许加密参数
			if err := c.validateAuthParams(); err != nil {
				return err
			}
			if c.PrivProtocol != "" || c.PrivPassword != "" {
				return errors.New("priv parameters not allowed for authNoPriv")
			}
		case SecLevelAuthPriv:
			// 有认证有加密：必须有认证和加密参数
			if err := c.validateAuthParams(); err != nil {
				return err
			}
			if err := c.validatePrivParams(); err != nil {
				return err
			}
		default:
			return errors.New("unsupported security level (noAuthNoPriv/authNoPriv/authPriv)")
		}
	default:
		return errors.New("unsupported snmp version (v1/v2c/v3)")
	}

	return nil
}

// 包内私有方法：根据版本解析默认配置
func parseDefaultConfig(userInput map[string]interface{}) SNMPConfig {
	if v, ok := userInput["version"].(string); ok {
		switch SNMPVersion(v) {
		case Version1, Version2c:
			return defaultV1V2cConfig
		case Version3:
			return defaultV3Config
		}
	}
	return defaultV1V2cConfig // 默认v2c
}

// 包内私有方法：解析用户输入（包含v3参数）
func (c *SNMPConfig) fromUserInput(input map[string]interface{}) error {
	// 通用参数解析
	if v, ok := input["version"].(string); ok && v != "" {
		switch SNMPVersion(v) {
		case Version1, Version2c, Version3:
			c.Version = SNMPVersion(v)
		default:
			return errors.New("unsupported snmp version (v1/v2c/v3)")
		}
	}
	if v, ok := input["community"].(string); ok {
		c.Community = v
	}
	if v, ok := input["port"].(int); ok {
		c.Port = v
	}
	if v, ok := input["timeout"].(int); ok {
		c.Timeout = v
	}
	if v, ok := input["retries"].(int); ok {
		c.Retries = v
	}
	if v, ok := input["source_address"].(string); ok {
		c.SourceAddress = v
	}
	if v, ok := input["max_repetitions"].(int); ok {
		c.MaxRepetitions = v
	}

	// v3专用参数解析
	if v, ok := input["username"].(string); ok {
		c.Username = v
	}
	if v, ok := input["security_level"].(string); ok {
		c.SecurityLevel = SecurityLevel(v)
	}
	if v, ok := input["auth_protocol"].(string); ok {
		c.AuthProtocol = v
	}
	if v, ok := input["auth_password"].(string); ok {
		c.AuthPassword = v
	}
	if v, ok := input["priv_protocol"].(string); ok {
		c.PrivProtocol = v
	}
	if v, ok := input["priv_password"].(string); ok {
		c.PrivPassword = v
	}
	if v, ok := input["context_name"].(string); ok {
		c.ContextName = v
	}

	return nil
}

// 包内私有方法：转换为gosnmp版本
func (c *SNMPConfig) getGoSNMPVersion() gosnmp.SnmpVersion {
	switch c.Version {
	case Version1:
		return gosnmp.Version1
	case Version2c:
		return gosnmp.Version2c
	case Version3:
		return gosnmp.Version3
	default:
		return gosnmp.Version2c
	}
}

// 包内私有方法：转换为超时时间
func (c *SNMPConfig) getTimeoutDuration() time.Duration {
	if c.Timeout == 0 {
		// 根据版本使用对应默认超时
		if c.Version == Version3 {
			return defaultV3Config.getTimeoutDuration()
		}
		return defaultV1V2cConfig.getTimeoutDuration()
	}
	return time.Duration(c.Timeout) * time.Second
}

// 包内私有方法：构建v3安全参数
func (c *SNMPConfig) buildV3SecurityParams() *gosnmp.UsmSecurityParameters {
	usm := &gosnmp.UsmSecurityParameters{
		UserName: c.Username,
	}

	// 配置认证参数
	switch c.AuthProtocol {
	case AuthMD5:
		usm.AuthenticationProtocol = gosnmp.MD5
	case AuthSHA:
		usm.AuthenticationProtocol = gosnmp.SHA
	case AuthSHA256:
		usm.AuthenticationProtocol = gosnmp.SHA256
	}
	usm.AuthenticationPassphrase = c.AuthPassword

	// 配置加密参数
	switch c.PrivProtocol {
	case PrivDES:
		usm.PrivacyProtocol = gosnmp.DES
	case PrivAES:
		usm.PrivacyProtocol = gosnmp.AES
	case PrivAES256:
		usm.PrivacyProtocol = gosnmp.AES256
	}
	usm.PrivacyPassphrase = c.PrivPassword

	return usm
}

// 包内私有方法：获取v3消息标志
func (c *SNMPConfig) getMsgFlags() gosnmp.SnmpV3MsgFlags {
	switch c.SecurityLevel {
	case SecLevelNoAuthNoPriv:
		return gosnmp.NoAuthNoPriv
	case SecLevelAuthNoPriv:
		return gosnmp.AuthNoPriv
	case SecLevelAuthPriv:
		return gosnmp.AuthPriv
	default:
		return gosnmp.NoAuthNoPriv
	}
}

// 包内私有方法：校验v3认证参数
func (c *SNMPConfig) validateAuthParams() error {
	if c.AuthPassword == "" {
		return errors.New("auth password is required for auth protocols")
	}
	switch c.AuthProtocol {
	case AuthMD5, AuthSHA, AuthSHA256:
		return nil
	default:
		return errors.New("unsupported auth protocol (MD5/SHA/SHA256)")
	}
}

// 包内私有方法：校验v3加密参数
func (c *SNMPConfig) validatePrivParams() error {
	if c.PrivPassword == "" {
		return errors.New("priv password is required for priv protocols")
	}
	switch c.PrivProtocol {
	case PrivDES, PrivAES, PrivAES256:
		return nil
	default:
		return errors.New("unsupported priv protocol (DES/AES/AES256)")
	}
}
